その他(中級)
■ インクリメント型エンコーダ読込
<試作品仕様>
・A相とB相からなるインクリメント型エンコーダ出力を読み込む
・C.W.(時計まわり) 、C.C.W.(反時計まわり)の 回転方向はA相パルスの立上りにおけるB相の極性により判別する。
・エンコーダA相からのパルスの数をカウントして液晶に表示する。
・液晶への表示は HEXスイッチの設定値により カウントを逓倍して表示する
HEXスイッチのメモリ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
b3 b2 b1 b0 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
N[倍] | 1 | 10 | 100 | 1000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 |
・0.25msec毎にA相の検出をおこない チャタリングが安定したらB相を読み込み回転方向を検出する。
・C.W.(時計まわり)にエンコーダのツマミを回したらカウント数が増加し、 、C.C.W.(反時計まわり)に回したらカウント数は減少すること。
・表示カウント数の最少値は0とする。
<試作品回路図>(→回路図のPDFファイル)
・ dsPIC4013をつかった場合の回路図を以下に示します。
・ エンコーダは秋月電子で販売されている インクリメント型エンコーダ アルファ EC16B (RE16F-40E3-L(A)-24P相当)です。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //******************************************************************* // 手動インクリメント型エンコーダ読込 // dsPIC4013 //******************************************************************* #include <p30f4013.h> #include <timer.h> #include <ports.h> #include "1lcd_lib_C30.h" #define b0 PORTBbits.RB5 #define b1 PORTBbits.RB4 #define b2 PORTBbits.RB3 #define b3 PORTBbits.RB2 _FOSC(CSW_FSCM_OFF & // クロック切り替えなし、フェールセイフクロックモニタなし HS2_PLL16 //外部発振子周波数 × postscaler × PLL:16倍 → 10MHz × 1/2 × 16 = 80MHz ); _FWDT(WDT_OFF); //ウォッチドックタイマ:OFF _FBORPOR(PBOR_ON & //ブラウンアウトリセット機能:ON BORV42 & //ブラウンアウト電圧:4.2V // BORV_42 & //ブラウンアウト電圧:4.2V (旧 config 記載形式) PWRT_64 & //パワーオンリセットタイマ64msec MCLR_EN //MCLR機能:ON ); _FGS(CODE_PROT_OFF); //コードプロテクト:OFF unsigned char dummy = ' '; signed long Count = 0; //FF入力周波数(エンコダカウント数 24パルス/回転) 32bit unsigned int Mag = 1; //エンコーダカウント数の周波数換算倍率 unsigned char AswCount = 0; //A相0検出回数 unsigned char nAswCount = 0; //A相1検出回数 unsigned char Asw; unsigned char Rising; char Buf[17]; //文字列のバッファー用レジスタ void delay_ms(unsigned int N) //1msec遅延関数 { __delay32(Clock/4000*N); //1msecのウェイト数: 80,000,000/4000 = 20,000 } void Mag_Func() //エンコーダカウント数−周波数倍率検出 //HEXスイッチ読み込み { if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Mag = 1; //0 else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0))Mag = 10; //1 else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1))Mag = 100; //2 else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0))Mag = 1000; //3 else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1))Mag = 10000; //4 else Mag = 10000; //3 } void _ISR _T1Interrupt(void) //液晶表示 { IFS0bits.T1IF = 0; //IFS0レジスタの T1IF(タイマ2の割込み検出)フラグリセット lcd_clear(); // 全消去 sprintf(Buf,"Count=%ld",Count);//arguementがないと遅い C30のバグ? lcd_str(Buf); lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"*%u(multiply)",Mag); //文字列としてバッファーに収納 lcd_str(Buf); } void Encode() //エンコーダ読み込み { Mag_Func(); //エンコーダ倍率 if(PORTAbits.RA11 == 0) AswCount++; //A相検出値が0なら AswCountをインクリメント else AswCount = 0; if(AswCount >= 8) { Asw = 0; //AswCount = 8 の時 A相は0である。 AswCount = 8; } if(PORTAbits.RA11 == 1)nAswCount++; //A相検出値が1なら nAswCountをインクリメント else nAswCount = 0; if(nAswCount >= 8) { if(Asw == 0)Rising = 1; //A相のパルスの立上り検出 Asw = 1; //nAswCount = 8 の時 A相は0である。 nAswCount = 8; } if(Rising == 1) //A相パルスが立上った場合 { Rising = 0; if(PORTDbits.RD9 == 0) { Count = Count + Mag; //C.W.の場合 if(Count >= 1000000)Count = 1000000; //最大 1000000 } else { Count = Count - Mag; //C.C.W.の場合 if(Count <= 0) Count = 0; } } __delay32(5000); //0.25msec(読み込み) } int main(void) { TRISA = 0xFFFF; ADPCFG = 0xFFFF; //デジタルポートに設定 TRISB = 0x003C; // TRISD = 0x0200; //RD9: in TRISF = 0; LATFbits.LATF4 = 1; //JK FF Q1 Clear Port → 1 LATFbits.LATF5 = 1; //JK FF Q2 Clear Port → 1 //T1タイマ 液晶表示 OpenTimer1( T1_ON & //タイマ1:ON T1_GATE_OFF & //ゲート制御(信号がある時だけタイマが動作)OFF T1_PS_1_256 & //プリスケーラ T1_SYNC_EXT_OFF & //外部同期タイマはタイマ1のみ T1_SOURCE_INT, 23438 //300msec / 0.05μsec / 256 = 23437.5 ); lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"Encoder %c",dummy);//arguementがないと遅い C30のバグ? lcd_str(Buf); //液晶表示 lcd_cmd(0xC0); //2目表示行目の先頭へ sprintf(Buf,"Start !! %c",dummy); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ2行 delay_ms(1000); ConfigIntTimer1(T1_INT_PRIOR_2 & T1_INT_ON ); //割込みレベル2 連結タイマ1割込みON EnableIntT1; //割込み許可 while(1) { Encode(); } return 0; } //************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等でに変更したものです。 //************************************************************************* #include "p30f4013.h" #define Clock 80000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB12 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB11 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB10 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB9 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATFbits.LATF0 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATFbits.LATF1 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 4000000); // 1μsecに要するウェイト回数 //__delay32(N) : Nが11以下の場合でも11回ウェイト _50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 4000); // 1msecに要するウェイト回数 // = Clock / 4000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
逓倍 | 液晶画面 上段: カウント表示 下段: 倍率 |
逓倍率 = 1 | ![]() |
逓倍率 = 10 | ![]() |
逓倍率 = 100 | ![]() |
逓倍率 = 1000 | ![]() |
逓倍率 = 10000 | ![]() |
■ パルスジェネレータ(0.5Hz〜200KHz)
<試作品仕様>
・周波数: 1.0Hz〜200KHz Duty:50%の矩形波パルスを発生すること。
・周波数の設定は手動インクリメント型エンコーダで行えること。
・周波数設定は ×1、×10、×100、×1000、×10000の 逓倍がHEXスイッチでおこなえること。
・周波数設定は0.5Hz単位でおこなえること。
<試作品回路図>(→回路図のPDFファイル)
・ dsPIC4013をつかった場合の回路図を以下に示します。
・ エンコーダは 秋月電子で販売されている インクリメント型エンコーダ アルファ EC16B (RE16F-40E3-L(A)-24P相当)です。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //******************************************************************* // パルスジェネレータ(0.5Hz 〜 200KHz) // dsPIC 16bit タイマ dsPIC4013 //★ ハード(JK フリップフロップ 74HC107)で1/2に分周しているので PIC単独での出力周波数は(1Hz〜400KHz) //******************************************************************* #include <p30f4013.h> #include <timer.h> #include <ports.h> #include "1lcd_lib_C30.h" #define b0 PORTBbits.RB5 #define b1 PORTBbits.RB4 #define b2 PORTBbits.RB3 #define b3 PORTBbits.RB2 _FOSC(CSW_FSCM_OFF & // クロック切り替えなし、フェールセイフクロックモニタなし HS2_PLL16 //外部発振子周波数 × postscaler × PLL:16倍 → 10MHz × 1/2 × 16 = 80MHz ); _FWDT(WDT_OFF); //ウォッチドックタイマ:OFF _FBORPOR(PBOR_ON & //ブラウンアウトリセット機能:ON BORV42 & //ブラウンアウト電圧:4.2V // BORV_42 & //ブラウンアウト電圧:4.2V (旧 config 記載形式) PWRT_64 & //パワーオンリセットタイマ64msec MCLR_EN //MCLR機能:ON ); _FGS(CODE_PROT_OFF); //コードプロテクト:OFF unsigned char dummy = ' '; signed long Freq = 2; //FF入力周波数(エンコダカウント数 24パルス/回転) 32bit unsigned int Mag = 1; //エンコーダカウント数の周波数換算倍率 unsigned int Duty_Count16 = 1000; //タイマ2の周期設定値(=FF入力周期[μsec]×20) 16bit unsigned long Duty_Count32 = 1000; //タイマ2の周期設定値(=FF入力周期[μsec]×20) 32bit unsigned char AswCount = 0; //A相0検出回数 unsigned char nAswCount = 0; //A相1検出回数 unsigned char Asw; unsigned char Rising; unsigned long Nduty; //T23のduty設定整数 int Quot = 0,Quot0 = 0; unsigned int Remain = 10000,Remain0 = 10000; int N ; char Buf[17]; //文字列のバッファー用レジスタ void delay_ms(unsigned int N) //1msec遅延関数 { __delay32(Clock/4000*N); //1msecのウェイト数: 80,000,000/4000 = 20,000 } void Mag_Func() //エンコーダカウント数−周波数倍率検出 //HEXスイッチ読み込み { if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Mag = 1; //0 else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0))Mag = 10; //1 else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1))Mag = 100; //2 else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0))Mag = 1000; //3 else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1))Mag = 10000; //4 else Mag = 10000; //3 } void _ISR _T1Interrupt(void) //液晶表示 { IFS0bits.T1IF = 0; //IFS0レジスタの T1IF(タイマ2の割込み検出)フラグリセット lcd_clear(); // 全消去 sprintf(Buf,"Freq=%lu.%lu[Hz]",Freq/2,(Freq % 2)* 5); //arguementがないと遅い C30のバグ? lcd_str(Buf); lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"*%u.%u(multiply)",Mag/2,(Mag%2)*5); //文字列としてバッファーに収納 lcd_str(Buf); } void Encode() //エンコーダ読み込み { Mag_Func(); //エンコーダ倍率 if(PORTAbits.RA11 == 0) AswCount++; //A相検出値が0なら AswCountをインクリメント else AswCount = 0; if(AswCount >= 8) { Asw = 0; //AswCount = 8 の時 A相は0である。 AswCount = 8; } if(PORTAbits.RA11 == 1)nAswCount++; //A相検出値が1なら nAswCountをインクリメント else nAswCount = 0; if(nAswCount >= 8) { if(Asw == 0)Rising = 1; //A相のパルスの立上り検出 Asw = 1; //nAswCount = 8 の時 A相は0である。 nAswCount = 8; } if(Rising == 1) //A相パルスが立上った場合 { Rising = 0; if(PORTDbits.RD9 == 0) { Freq = Freq + Mag; //C.W.の場合 if(Freq >= 400000)Freq = 400000; //最大400KHz } else { Freq = Freq - Mag; //C.C.W.の場合 if(Freq <= 2) Freq = 2; } Duty_Count32 = 20000000/Freq; //Duty_Count = 50カウント × 400,000Hz/Fre //2.5μsec(=1/400,000Hz) = 0.05μsec(=1/80,000,000Hz)×50カウント if(Duty_Count32 <= 65535) { Duty_Count16 = (unsigned int)Duty_Count32; } else { //Duty0 = 0.05μsec × 65535 = 32767.5μsec = 32.7675mse //32767.5×50 = 1638375 Quot = Duty_Count32/65535 ; //Quotient 商 Remain = Duty_Count32 % 65535; //Remainder 余り } } __delay32(5000); //0.25msec(読み込み) } void _ISR _T2Interrupt(void) //パルス出力 { if(Duty_Count32 <= 65535) //16ビット・高周波の場合 { LATDbits.LATD0 = 0; //Q LATDbits.LATD1 = 0; //nQ PR2 = Duty_Count16; //割り込み発生までの時間設定 //50カウント → 2.5μsec(=400KHz) LATDbits.LATD0 = 1; // LATDbits.LATD1 = 1; // } else //16ビット以上の低周波の場合 { if(Quot0 == 0) //パルスを出す場合 { LATDbits.LATD0 = 0; //Q LATDbits.LATD1 = 0; //nQ PR2 = Remain0; //余りを割り込み待ち時間に設定 Quot0 = Quot; //現時点の商を記憶 Remain0 = Remain; //現時点の余りを記憶 LATDbits.LATD0 = 1; // LATDbits.LATD1 = 1; // } else { Quot0 = Quot0 - 1; // パルスを出さないで割り込み終了 PR2 = 65535; } } IFS0bits.T2IF = 0; //IFS0レジスタの T2IF(タイマ2の割込み検出)フラグリセット } int main(void) { TRISA = 0xFFFF; ADPCFG = 0xFFFF; //デジタルポートに設定 TRISB = 0x003C; // TRISD = 0x0200; //RD9: in TRISF = 0; LATFbits.LATF4 = 1; //JK FF Q1 Clear Port → 1 LATFbits.LATF5 = 1; //JK FF Q2 Clear Port → 1 //T1タイマ 液晶表示 OpenTimer1( T1_ON & //タイマ1:ON T1_GATE_OFF & //ゲート制御(信号がある時だけタイマが動作)OFF T1_PS_1_256 & //プリスケーラ T1_SYNC_EXT_OFF & //外部同期タイマはタイマ1のみ T1_SOURCE_INT, 23438 //300msec / 0.05μsec / 256 = 23437.5 ); //T2タイマ パルス出力 OpenTimer2( T2_ON & //連結タイマ2・タイマ3:ON T2_GATE_OFF & //ゲート制御OFF T2_PS_1_1 & //プリスケーラ 1/1 T2_SOURCE_INT, //クロック源: 内部クロック // 80MHz Fosc * 1/4 = 20MHz → 0.05μsec 100 // 2.5μsec(= 0.05μsec × 50) → 400KHz // 実測:2.5μsec ); lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"Pulse Generator2 %c",dummy);//arguementがないと遅い C30のバグ? lcd_str(Buf); //液晶表示 lcd_cmd(0xC0); //2目表示行目の先頭へ sprintf(Buf,"Start !! %c",dummy); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ2行 delay_ms(1000); ConfigIntTimer1(T1_INT_PRIOR_2 & T1_INT_ON ); //割込みレベル2 連結タイマ1割込みON ConfigIntTimer2(T2_INT_PRIOR_5 & T2_INT_ON ); //割込みレベル5 連結タイマ2割込みON EnableIntT1; EnableIntT2; //割込み許可 while(1) { Encode(); } return 0; } //************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等でに変更したものです。 //************************************************************************* #include "p30f4013.h" #define Clock 80000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB12 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB11 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB10 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB9 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATFbits.LATF0 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATFbits.LATF1 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 4000000); // 1μsecに要するウェイト回数 //__delay32(N) : Nが11以下の場合でも11回ウェイト _50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 4000); // 1msecに要するウェイト回数 // = Clock / 4000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
出力周波数 | 液晶表示 | パルス波形(フリップフロップ出力) | フリップフロップ入力波形 (PIC出力波形) |
1.0Hz | ![]() |
![]() |
ー |
10Hz | ![]() |
![]() |
ー |
100Hz | ![]() |
![]() |
ー |
1KHzHz | ![]() |
![]() |
ー |
10KHz |
![]() |
![]() |
ー |
100KHz | ![]() |
![]() |
ー |
200KHz | ![]() |
![]() |
![]() |
■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 16進数表示
<HI-TECH編>
液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
・制御対象は7セグメント液晶1個とする。
・16進スイッチの値を 液晶に16進数で表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれまし
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //HI-TEC セグメント液晶スタティック制御 PIC16F1937 // Hex SW 16進表示 #include <htc.h> #define _XTAL_FREQ 500000 //セラミック発振子:20MHz (この設定で ディレイ関数__delay_ms()が設計の遅れ時間となる 原因不明 バグ?) //#define _XTAL_FREQ 20000000 //セラミック発振子:20MHz ディレイ関数用 // コンフィギュレーションの設定 __CONFIG( FOSC_HS & // EXTRC Oscillator, RC on RA7/OSC1/CLKIN WDTE_OFF & // Power-up Timer Enable bit// PWRT disabled PWRTE_ON & // MCLR Pin Function Select// RE3/MCLR/VPP pin function is MCLR MCLRE_ON & // RE3/MCLR/VPP pin function is digital input CP_OFF & // Program memory code protection is enabled CPD_OFF & // Data memory code protection is enabled BOREN_OFF & // Clock Out Enable bit// CLKOUT function is disabled. I/O or oscillator function on RA6/CLKOUT CLKOUTEN_OFF & // CLKOUT function is enabled on RA6/CLKOUT pin IESO_OFF & // Fail Clock Monitor Enable// Fail-Safe Clock Monitor is enabled FCMEN_ON // Fail-Safe Clock Monitor is disabled ); __CONFIG( WRT_OFF & // 000h to 1FFh write protected, 200h to 1FFFh may be modified by EECON control PLLEN_OFF & // 4x PLL disabled (PLLをONにしても動作時間に影響ない 原因不明 バグ?) STVREN_OFF &// Brown-out Reset Voltage selection// Brown-out Reset Voltage (VBOR) set to 1.9 V // BORV_19 & // Brown-out Reset Voltage (VBOR) set to 2.7 V // DEBUG_OFF & // Background debugger is enabled LVP_OFF // HV on MCLR/VPP must not be used for programming ); #define b0 PORTCbits.RC3 #define b1 PORTCbits.RC2 #define b2 PORTCbits.RC1 #define b3 PORTCbits.RC0 unsigned int Seg[16] = {0b00111111, //0 0b00000110, //1 0b01011011, // 2 0b01001111, // 3 0b01100110, // 4 0b01101101, // 5 0b01111101, // 6 0b00000111, // 7 0b01111111, // 8 0b01101111, // 9 0b01110111, //A 0b01111100, //b 0b00111001, //C 0b01011110, //d 0b01111001, //E 0b01110001}; //F unsigned int Count; void delay_ms(unsigned long int msec) //1msec delay function { while(msec) { msec--; __delay_ms(1); //1msec delay } } void main() { ANSELA = 0; //Aポートをデジタルポートに ANSELB = 0; //Bポートをデジタルポートに ANSELE = 0; //Eポートをデジタルポートに TRISA = 0; TRISB = 0; TRISC = 0x0F; //b0-b3 in port // LCDPSレジスタ(位相レジスタ) LCDPSbits.WFT = 0; //タイプAの位相が各コモンタイプ内で変化する LCDPSbits.BIASMD = 0; //スタティックバイアスモードの場合は0にセット LCDPSbits.LCDA = 0; //LCDドライバモジュールは非アクティブ LCDPSbits.WA = 0; // LCDへの書き込みは許可されていない。 LCDPSbits.LP3 = 0; //LDCクロックのプリスケーラ 0000: 1/1 LCDPSbits.LP2 = 0; //1111: 1/16 1000: 1/9 etc LCDPSbits.LP1 = 0; LCDPSbits.LP0 = 0; // LCDPS = 0x08; // タイプAでスタティック、1:9 LCDSE1 = 0xFF; // セグメント1の全セグメント有効化 // LCDSE0 = 0xFF; // 全セグメント有効化 // LCDSE1 = 0xFF; // 全セグメント有効化 // LCDSE2 = 0xFF; // 全セグメント有効化 //LCDCONレジスタ(LCDドライバ有効・無効、LCDクロックソース選択) LCDCONbits.LCDEN = 1; //LCDドライバー: 有効 LCDCONbits.SLPEN = 0; //スリープ時のLCDドライバー: 無効 LCDCONbits.WERR = 0; // LCDの書き込みエラーなし LCDCONbits.CS0 = 0; //LCDクロックソース選択ビット LCDCONbits.CS1 = 0; //同上 //00:Fosc/256 //01:T1OSC(Timer1) 1x:LFINTOSC(31KHz) //LCDCON = 0x84;//0b10000100 // スタティック、副発振有効itits LCDCONbits.LMUX1 = 0; //00: スタティック制御 //スタティック・マルチプレックス制御選択 LCDCONbits.LMUX0 = 0; //01: 1/2マルチプレックス、 02: 1/3マルチプレックス、 03: 1/4マルチプレックス //LCDDATA1-3レジスタ(データレジスタ) LCDDATA1 = 0xFF; // セグメント1の全セグメントオン //LCDDATA0 = 0xFF; // 全セグメントオン //LCDDATA1 = 0xFF; // 全セグメントオン //LCDDATA2 = 0xFF; // 全セグメントオン //LCDRLレジスタ(リファレンス ラダー) クロック極性切り替わり時の抵抗値設定、AモードとBモードとの割合設定による省電力に係るレジスタ LCDRLbits.LRLAP1 = 0; //LCDリファレンスラダーAタイムの電力制御ビット LCDRLbits.LRLAP0 = 1; //同上 //01: 低電力モード // 10: 中電力モード 11: 高電力モード LCDRLbits.LRLBP1 = 0; //LCDリファレンスラダーBタイムの電力制御ビット LCDRLbits.LRLBP0 = 1; //同上 //01: 低電力モード //10: 中電力モード 11: 高電力モード LCDRLbits.LRLAT2 = 1; //LCDリファレンスラダーAタイムインターバル制御ビットs LCDRLbits.LRLAT1 = 1; //同上 LCDRLbits.LRLAT0 = 1; //同上 //111: (WFT=0が選択してあるので)タイプAの波形は、内部LCDリファレンスが、7クロック間電力モードAで9クロック間電力モードBとなる。 //111: (WFT=1を選択している場合は)タイプBの波形は、内部LCDリファレンスが、7クロック間電力モードAで25クロック間電力モードBとなる。 // LCDRL = 0x57; // 低電流モード //LCDREFレジスタ(リファレンス電圧設定、LCDバイアス電圧設定) LCDREFbits.LCDIRE = 1; //1: 内部リファレンス有効 //0: 無効 LCDREFbits.LCDIRS = 0; //0: LCDの内部のコントラスト制御はVddを使用する。 //内部のリファレンス電圧のソース電源選択ビット //1: LCDの内部のコントラスト制御はFVRの3.072Vを使用する。 LCDREFbits.LCDIRI = 0; //内部リファレンスラダーアイドルイネーブルビット //0: LCDのFVRバッファーは、LCDリファレンスのパワーモードを無視する。 LCDREFbits.VLCD3PE = 0; //VCLD3ピンは接続されない //外部LCDバイアス電圧を使用する場合に接続する LCDREFbits.VLCD2PE = 0; //VCLD2ピンは接続されない LCDREFbits.VLCD1PE = 0; //VCLD1ピンは接続されない // LCDREF = 0x80; //0b10000000 // 内蔵バイアス、VLCD入力なし //LCDCSTレジスタ(コントラスト設定) LCDCSTbits.LCDCST2 = 0; //LCDのコントラスト制御ビット LCDCSTbits.LCDCST1 = 1; //同上 LCDCSTbits.LCDCST0 = 1; //同上 //011 ラダー抵抗は最大抵抗の3/7、コントラストは中程度 //000 ラダー抵抗は最小(ラダー抵抗は短絡)、最大コントラスト //111 ラダー抵抗は最大、最小コントラスト //LCDCST = 0x03; //0b00000011 // 中コントラスト //T1CON レジスタ(Timer1 Control Resister) TMR1CS1 = 0; //Timer1 clock source: Fosc/4 //Timer1 Clock Source Select bits TMR1CS0 = 0; //TMR1CS<1:0> = 00 → Fosc/4 // 01 → Fosc T1CKPS1 = 0; //プリスケーラ 1/1 //Prescale Select bits T1CKPS0 = 0; //T1CKPS<1:0> = 00 → 1/1 //10→1/4 01→1/2 00→1/1 T1OSCEN = 0; //LP Oscillator Enble Control bit nT1SYNC = 0; //Timer1 External Clock Input Synchronization Control bit TMR1ON = 1; //Enable Timer1 //Timer1 On bit //T1GCON レジスタ(Timer1 Gate Control Resister) // ゲート機能なし TMR1GE = 0; //Timer1 Gate Enable bit T1GPOL = 0; //Timer1 Gate Polarity bit T1GTM = 0; //Timer1 Gate Toggle Mode bit T1GSPM = 0; //Timer1 Gate Single Pulse Mode bit T1GGO = 0; //Timer1 Gate Single-Pulse Acquisition Status bit T1GVAL = 0; //Timer1 Gate current State bit T1GSS1 = 0; //Timer1 Gate Source Select bits T1GSS0 = 0; TMR1H = 0xFB; // TMR1L = 0x1E; // __delay_ms(1); while(1) { if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[0]; else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[1]; else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[2]; else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0)) LCDDATA1 = Seg[3]; else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[4]; else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[5]; else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[6]; else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 0)) LCDDATA1 = Seg[7]; else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[8]; else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[9]; else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[10]; else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 0)) LCDDATA1 = Seg[11]; else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[12]; else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[13]; else if((b3 == 0) && (b2 == 0) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[14]; else LCDDATA1 = Seg[15]; } }
<動作結果>
HEX スイッチをFに回した時の写真です。
液晶表示 | 電圧波形 |
|
表示セグメント セグメント印加電圧 上段: 4A(2v/div) 下段: COM(2v/div) |
非表示セグメント 上段: 4B(2v/div) 下段: COM(2v/div) |
|
![]() |
![]() |
![]() |
25msec/div デジタルオシロスコープ ATTEN製(中国) ADS1102CA |
■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 カウンタ
<HI-TECH編>
液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
・制御対象は7セグメント液晶1個とする。
・周期1秒の16進カウンタを製作のこと。 また、 Fの次は 0に戻ること
すなわち 0 → 1 → 2 → 3 ……… C → d → E → F → 0 → 1
<試作品回路図>(→回路図のPDFファイル)
PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //HI-TEC セグメント液晶スタティック制御 PIC16F1937 // 1桁 16進カウンタ #include <htc.h> #define _XTAL_FREQ 500000 //セラミック発振子:20MHz (この設定で ディレイ関数__delay_ms()が設計の遅れ時間となる 原因不明 バグ?) //#define _XTAL_FREQ 20000000 //セラミック発振子:20MHz ディレイ関数用 // コンフィギュレーションの設定 __CONFIG( FOSC_HS & // EXTRC Oscillator, RC on RA7/OSC1/CLKIN WDTE_OFF & // Power-up Timer Enable bit// PWRT disabled PWRTE_ON & // MCLR Pin Function Select// RE3/MCLR/VPP pin function is MCLR MCLRE_ON & // RE3/MCLR/VPP pin function is digital input CP_OFF & // Program memory code protection is enabled CPD_OFF & // Data memory code protection is enabled BOREN_OFF & // Clock Out Enable bit// CLKOUT function is disabled. I/O or oscillator function on RA6/CLKOUT CLKOUTEN_OFF & // CLKOUT function is enabled on RA6/CLKOUT pin IESO_OFF & // Fail Clock Monitor Enable// Fail-Safe Clock Monitor is enabled FCMEN_ON // Fail-Safe Clock Monitor is disabled ); __CONFIG( WRT_OFF & // 000h to 1FFh write protected, 200h to 1FFFh may be modified by EECON control PLLEN_OFF & // 4x PLL disabled (PLLをONにしても動作時間に影響ない 原因不明 バグ?) STVREN_OFF &// Brown-out Reset Voltage selection// Brown-out Reset Voltage (VBOR) set to 1.9 V // BORV_19 & // Brown-out Reset Voltage (VBOR) set to 2.7 V // DEBUG_OFF & // Background debugger is enabled LVP_OFF // HV on MCLR/VPP must not be used for programming ); unsigned int Seg[16] = {0b00111111, //0 0b00000110, //1 0b01011011, // 2 0b01001111, // 3 0b01100110, // 4 0b01101101, // 5 0b01111101, // 6 0b00000111, // 7 0b01111111, // 8 0b01101111, // 9 0b01110111, //A 0b01111100, //b 0b00111001, //C 0b01011110, //d 0b01111001, //E 0b01110001}; //F unsigned int Count; int ix ; void delay_ms(unsigned long int msec) //1msec delay function { while(msec) { msec--; __delay_ms(1); //1msec delay } } void interrupt isr(void) //10msec毎の割り込み { TMR1IF = 0; //フラグクリア //アップカウンタの値設定 //Clock: 20MHz/4 → 5MHz 0.2μsec // 10msec毎の割り込みを行う //プリスケーラ 1/1 //Prescale Select bits // <計算> // (65536 -N)*0.2*1 = 10000 [μsec] // N = 65536 - 50000 = 15536 // 15536 = 0x3C6B 実測割り込みインターバル = 400msec(原因不明 バグ?) // 対応: 10000μsec * 1/40 = 250μsec // (56636 -N)*0.2*1 = 250 [μsec] // N = 65536 - 1250 = 642486 = 0xFB1E (実測割り込みインターバル: 10msec) TMR1H = 0xFB; // TMR1L = 0x1E; // Count++; if(Count >= 100) { Count = 0; LCDDATA1 = Seg[ix]; //液晶セグメント表示 ix++; if(ix >=16)ix = 0; } } void main() { ANSELA = 0; //Aポートをデジタルポートに ANSELB = 0; //Bポートをデジタルポートに ANSELE = 0; //Eポートをデジタルポートに TRISA = 0; TRISB = 0; TRISC = 0; // LCDPSレジスタ(位相レジスタ) LCDPSbits.WFT = 0; //タイプAの位相が各コモンタイプ内で変化する LCDPSbits.BIASMD = 0; //スタティックバイアスモードの場合は0にセット LCDPSbits.LCDA = 0; //LCDドライバモジュールは非アクティブ LCDPSbits.WA = 0; // LCDへの書き込みは許可されていない。 LCDPSbits.LP3 = 0; //LDCクロックのプリスケーラ 0000: 1/1 LCDPSbits.LP2 = 0; //1111: 1/16 1000: 1/9 etc LCDPSbits.LP1 = 0; LCDPSbits.LP0 = 0; // LCDPS = 0x08; // タイプAでスタティック、1:9 LCDSE1 = 0xFF; // セグメント1の全セグメント有効化 // LCDSE0 = 0xFF; // 全セグメント有効化 // LCDSE1 = 0xFF; // 全セグメント有効化 // LCDSE2 = 0xFF; // 全セグメント有効化 //LCDCONレジスタ(LCDドライバ有効・無効、LCDクロックソース選択) LCDCONbits.LCDEN = 1; //LCDドライバー: 有効 LCDCONbits.SLPEN = 0; //スリープ時のLCDドライバー: 無効 LCDCONbits.WERR = 0; // LCDの書き込みエラーなし LCDCONbits.CS0 = 0; //LCDクロックソース選択ビット LCDCONbits.CS1 = 0; //同上 //00:Fosc/256 //01:T1OSC(Timer1) 1x:LFINTOSC(31KHz) //LCDCON = 0x84;//0b10000100 // スタティック、副発振有効itits LCDCONbits.LMUX1 = 0; //00: スタティック制御 //スタティック・マルチプレックス制御選択 LCDCONbits.LMUX0 = 0; //01: 1/2マルチプレックス、 02: 1/3マルチプレックス、 03: 1/4マルチプレックス //LCDDATA1-3レジスタ(データレジスタ) LCDDATA1 = 0xFF; // セグメント1の全セグメントオン //LCDDATA0 = 0xFF; // 全セグメントオン //LCDDATA1 = 0xFF; // 全セグメントオン //LCDDATA2 = 0xFF; // 全セグメントオン //LCDRLレジスタ(リファレンス ラダー) クロック極性切り替わり時の抵抗値設定、AモードとBモードとの割合設定による省電力に係るレジスタ LCDRLbits.LRLAP1 = 0; //LCDリファレンスラダーAタイムの電力制御ビット LCDRLbits.LRLAP0 = 1; //同上 //01: 低電力モード // 10: 中電力モード 11: 高電力モード LCDRLbits.LRLBP1 = 0; //LCDリファレンスラダーBタイムの電力制御ビット LCDRLbits.LRLBP0 = 1; //同上 //01: 低電力モード //10: 中電力モード 11: 高電力モード LCDRLbits.LRLAT2 = 1; //LCDリファレンスラダーAタイムインターバル制御ビットs LCDRLbits.LRLAT1 = 1; //同上 LCDRLbits.LRLAT0 = 1; //同上 //111: (WFT=0が選択してあるので)タイプAの波形は、内部LCDリファレンスが、7クロック間電力モードAで9クロック間電力モードBとなる。 //111: (WFT=1を選択している場合は)タイプBの波形は、内部LCDリファレンスが、7クロック間電力モードAで25クロック間電力モードBとなる。 // LCDRL = 0x57; // 低電流モード //LCDREFレジスタ(リファレンス電圧設定、LCDバイアス電圧設定) LCDREFbits.LCDIRE = 1; //1: 内部リファレンス有効 //0: 無効 LCDREFbits.LCDIRS = 0; //0: LCDの内部のコントラスト制御はVddを使用する。 //内部のリファレンス電圧のソース電源選択ビット //1: LCDの内部のコントラスト制御はFVRの3.072Vを使用する。 LCDREFbits.LCDIRI = 0; //内部リファレンスラダーアイドルイネーブルビット //0: LCDのFVRバッファーは、LCDリファレンスのパワーモードを無視する。 LCDREFbits.VLCD3PE = 0; //VCLD3ピンは接続されない //外部LCDバイアス電圧を使用する場合に接続する LCDREFbits.VLCD2PE = 0; //VCLD2ピンは接続されない LCDREFbits.VLCD1PE = 0; //VCLD1ピンは接続されない // LCDREF = 0x80; //0b10000000 // 内蔵バイアス、VLCD入力なし //LCDCSTレジスタ(コントラスト設定) LCDCSTbits.LCDCST2 = 0; //LCDのコントラスト制御ビット LCDCSTbits.LCDCST1 = 1; //同上 LCDCSTbits.LCDCST0 = 1; //同上 //011 ラダー抵抗は最大抵抗の3/7、コントラストは中程度 //000 ラダー抵抗は最小(ラダー抵抗は短絡)、最大コントラスト //111 ラダー抵抗は最大、最小コントラスト //LCDCST = 0x03; //0b00000011 // 中コントラスト //T1CON レジスタ(Timer1 Control Resister) TMR1CS1 = 0; //Timer1 clock source: Fosc/4 //Timer1 Clock Source Select bits TMR1CS0 = 0; //TMR1CS<1:0> = 00 → Fosc/4 // 01 → Fosc T1CKPS1 = 0; //プリスケーラ 1/1 //Prescale Select bits T1CKPS0 = 0; //T1CKPS<1:0> = 00 → 1/1 //10→1/4 01→1/2 00→1/1 T1OSCEN = 0; //LP Oscillator Enble Control bit nT1SYNC = 0; //Timer1 External Clock Input Synchronization Control bit TMR1ON = 1; //Enable Timer1 //Timer1 On bit //T1GCON レジスタ(Timer1 Gate Control Resister) // ゲート機能なし TMR1GE = 0; //Timer1 Gate Enable bit T1GPOL = 0; //Timer1 Gate Polarity bit T1GTM = 0; //Timer1 Gate Toggle Mode bit T1GSPM = 0; //Timer1 Gate Single Pulse Mode bit T1GGO = 0; //Timer1 Gate Single-Pulse Acquisition Status bit T1GVAL = 0; //Timer1 Gate current State bit T1GSS1 = 0; //Timer1 Gate Source Select bits T1GSS0 = 0; TMR1H = 0xFB; // TMR1L = 0x1E; // TMR1IE = 1; // タイマ1割り込み許可 PEIE = 1; // 周辺割り込み許可許可 GIE = 1; // グローバル割り込み許可 __delay_ms(1); while(1) { /* for(ix = 0; ix<16; ix++) { LCDDATA1 = Seg[ix]; delay_ms(1000); } */ } }
<動作結果>
6がカウントされ 液晶に表示された場合の写真です。
■ 外付けXORによる 液晶セグメント スタティック駆動式 16進数表示
液晶の各セグメントに印加される平均電圧は0vにする必要があります。
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動により各液晶セグメントを直接制御する
・PICの出力I/Oは スタティック液晶駆動用ではない一般のI/Oを用い、 外付け回路により液晶印可電圧平均値を0Vにすること。
・液晶の駆動周波数は302Hzとする。
・制御対象は7セグメント液晶1個とする。
・16進スイッチの値を 液晶に16進数で表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> // XORを使用した 液晶セグメントスタティック駆動制御 // HeXスイッチの値表示 // PIC18F452, C18コンパイラ #include <p18f452.h> #include <delays.h> #pragma config OSC = HS // f = 20MHz #pragma config WDT = OFF #pragma config LVP = OFF //入力ポート 設定 #define b0 PORTDbits.RD0 #define b1 PORTCbits.RC3 #define b2 PORTCbits.RC1 #define b3 PORTCbits.RC0 //出力ポート 設定 #define A PORTCbits.RC7 #define B PORTCbits.RC6 #define C PORTCbits.RC5 #define D PORTCbits.RC4 #define E PORTAbits.RA0 #define F PORTBbits.RB7 #define G PORTBbits.RB6 void Func_0(){G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;} // 0 を表示 void Func_1(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;} // 1 を表示 void Func_2(){G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;} // 2 を表示 void Func_3(){G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;} //3 を表示 void Func_4(){G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;} //4 を表示 void Func_5(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;} //5 を表示 void Func_6(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;} //6 を表示 void Func_7(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;} //7 を表示 void Func_8(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;} //8 を表示 void Func_9(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;} //9 を表示 void Func_A(){G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;} //A を表示 void Func_b(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;} //b を表示 void Func_C(){G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;} //C を表示 void Func_d(){G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;} //d を表示 void Func_E(){G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;} //E を表示 void Func_F(){G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;} //F を表示 void delay_ms (long int cycle) // CCSコンパイラと同じ delay_ms(long int) 関数を設計 { long int i = 0; for (i = 0; i < cycle*5; i++)Delay1KTCYx(1); // 0.05μsec × 4 × 1000 = 0.2msec } void main (void) { TRISA = 0; TRISB = 0; TRISC = 0b00001011; TRISD = 0b00000001; // CCP: PWMモード 1.2KHz duty=1/2 T2CONbits.T2CKPS1 = 1; // prescale: 1/16 CCP1CON = 0b00111111; //bit5,4 PWM duty cycle //bit3,2 =11 → PWM mode PR2 = 0xFF; // PWM period = (PR2 + 1)*4*Tosc*(TMR2prescale value) TMR2 = 0x7F; // = (256 + 1) * 4 * 0.05μsec * 16 T2CONbits.TMR2ON = 1; // = 822.4μsec = 0.8224msec(1.215KHz)(実測:1.22KHz) → 液晶クロック=1.21KHz / 4 = 302Hz CCPR1L = 0x7F; // PWM duty cycle = CCPR1L:CCPCON<5:4> * Tosc * (TMR2prescale value) // = 0b01111111 11(511) * 0.05 * 256 // while (1) { if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Func_0(); else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_1(); else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_2(); else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_3(); else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_4(); else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_5(); else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_6(); else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 0)) Func_7(); else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 1)) Func_8(); else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_9(); else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_A(); else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_b(); else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_C(); else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_d(); else if((b3 == 0) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_E(); else Func_F(); /* PORTDbits.RD1 = 0; // RD1 LED ON delay_ms(1000); //1000msec delay PORTDbits.RD1 = 1; // BポートのLED OFF delay_ms(1000); // 1000msec delay */ } }
<動作結果>
HEXスイッチの7を選択した時の表示の写真です。
液晶表示 | 電圧波形 |
|
表示液晶セグメント 上段: 4A (2v/div) 下段: COM (2v/div) |
非表示液晶セグメント 上段: 4G(2v/div) 下段: COM(2v/div) |
|
![]() |
![]() |
![]() |
1msec/div デジタルオシロスコープ ATTEN製(中国) ADS1102CA |
■ 外付けXORによる 液晶セグメント スタティック駆動式 カウンタ
液晶の各セグメントに印加される平均電圧は0vにする必要があります。
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動により各液晶セグメントを直接制御する
・PICの出力I/Oは スタティック液晶駆動用ではない一般のI/Oを用い、 外付け回路により液晶印可電圧平均値を0Vにすること。
・液晶の駆動周波数は302Hzとする。
・制御対象は7セグメント液晶1個とする。
・周期1秒の16進カウンタを製作のこと。 また、 Fの次は 0に戻ること
すなわち 0 → 1 → 2 → 3 ……… C → d → E → F → 0 → 1
<試作品回路図>(→回路図のPDFファイル)
PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> // XORを使用した 液晶セグメントスタティック駆動制御 // カウンタ // PIC18F452, C18コンパイラ #include <p18f452.h> #include <delays.h> #include <timers.h> #pragma config OSC = HS // f = 20MHz #pragma config WDT = OFF #pragma config LVP = OFF //出力ポート 設定 #define A PORTCbits.RC7 #define B PORTCbits.RC6 #define C PORTCbits.RC5 #define D PORTCbits.RC4 #define E PORTAbits.RA0 #define F PORTBbits.RB7 #define G PORTBbits.RB6 unsigned long int Count1 = 0; unsigned long int Count2 = 0; int LED = 0; void Func_0(){G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;} // 0 を表示 void Func_1(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;} // 1 を表示 void Func_2(){G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;} // 2 を表示 void Func_3(){G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;} //3 を表示 void Func_4(){G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;} //4 を表示 void Func_5(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;} //5 を表示 void Func_6(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;} //6 を表示 void Func_7(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;} //7 を表示 void Func_8(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;} //8 を表示 void Func_9(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;} //9 を表示 void Func_A(){G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;} //A を表示 void Func_b(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;} //b を表示 void Func_C(){G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;} //C を表示 void Func_d(){G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;} //d を表示 void Func_E(){G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;} //E を表示 void Func_F(){G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;} //F を表示 void delay_ms (long int cycle) // CCSコンパイラと同じ delay_ms(long int) 関数を設計 { long int i = 0; for (i = 0; i < cycle*5; i++)Delay1KTCYx(1); // 0.05μsec × 4 × 1000 = 0.2msec } #pragma interrupt my_Func // 10msec タイマ1 インターバル割り込み #pragma code isrcode = 0x08 void isr_direct(void) { _asm goto my_Func _endasm } #pragma code void my_Func(void) { PIR1bits.TMR1IF = 0; // タイマ1割り込みフラグをクリアする WriteTimer1(59286); // 0.05μsec × 4 × 8 × 6250 = 10000μsec = 10msec (at システムクロック20MHz) // 256×256 - 6250 = 59286 // タイマ0:16bitアップカウントタイマ → オーバーフローで割込み発生 Count1++; if(Count1 >= 100) //1秒毎に { Count1 = 0; if(Count2 == 0)Func_0(); else if(Count2 == 1) Func_1(); else if(Count2 == 2) Func_2(); else if(Count2 == 3) Func_3(); else if(Count2 == 4) Func_4(); else if(Count2 == 5) Func_5(); else if(Count2 == 6) Func_6(); else if(Count2 == 7) Func_7(); else if(Count2 == 8) Func_8(); else if(Count2 == 9) Func_9(); else if(Count2 == 10) Func_A(); else if(Count2 == 11) Func_b(); else if(Count2 == 12) Func_C(); else if(Count2 == 13) Func_d(); else if(Count2 == 14) Func_E(); else Func_F(); Count2++; if(Count2 >= 16)Count2 = 0; if(LED == 1) { PORTDbits.RD1 = 0; // RD1 LED ON LED = 0; } else { PORTDbits.RD1 = 1; // BポートのLED OFF LED = 1; } } } void main (void) { TRISA = 0; TRISB = 0; TRISC = 0b00001011; TRISD = 0b00000001; // CCP: PWMモード 1.2KHz duty=1/2 T2CONbits.T2CKPS1 = 1; // prescale: 1/16 CCP1CON = 0b00111111; //bit5,4 PWM duty cycle //bit3,2 =11 → PWM mode PR2 = 0xFF; // PWM period = (PR2 + 1)*4*Tosc*(TMR2prescale value) TMR2 = 0x7F; // = (256 + 1) * 4 * 0.05μsec * 16 T2CONbits.TMR2ON = 1; // = 822.4μsec = 0.8224msec(1.215KHz)(実測:1.22KHz) → 液晶クロック=1.21KHz / 4 = 302Hz CCPR1L = 0x7F; // PWM duty cycle = CCPR1L:CCPCON<5:4> * Tosc * (TMR2prescale value) // = 0b01111111 11(511) * 0.05 * 256 // //タイマ0の設定 OpenTimer1 ( TIMER_INT_ON & //割込み:ON T1_16BIT_RW & //16 bit モードに設定 vs 8bit モード( T0_8BIT ) T1_SOURCE_INT & //内部クロック使用 T1_PS_1_8 & //8ビットプリスケーラ 1/8 vs 1/1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 T1_OSC1EN_OFF ); WriteTimer1(59286); RCONbits.IPEN = 0; //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0) PIE1bits.TMR1IE = 1; //タイマ1割込み許可 INTCONbits.PEIE =1; //周辺割込み許可 //INTCONレジスタの b6ビット : 低位割込み許可/禁止(割り込み優先順位制御 有りの場合) INTCONbits.GIE = 1; //全割込み許可 //INTCONレジスタの b7ビット : 高位割込み許可/禁止(割り込み優先順位制御 有りの場合) while (1) { } }
<動作結果>
カウント値が9の時の写真です。
■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 16進数表示
<C18編>
液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
・制御対象は7セグメント液晶1個とする。
・16進スイッチの値を 液晶に16進数で表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC18F85J90、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
PIM内部の接続は何故かトリッキーな接続となっているので設計には十分気おつけることが必要です。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれまし
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> /* HexSwの値を LCDに表示 */ #include <p18f85J90.h> #include <stdio.h> #include <delays.h> #pragma config FOSC = HS // システムクロック=20MHz #pragma config XINST = OFF #pragma config WDTEN = OFF //ウォッチドックタイマ OFF //入力ポート 設定 #define b0 PORTHbits.RH0 #define b1 PORTGbits.RG2 #define b2 PORTCbits.RC1 #define b3 PORTGbits.RG3 void Func_0(){LCDDATA0 = 0b0111111;} // 0 を表示 //G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1; void Func_1(){LCDDATA0 = 0b00000110;} // 1 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0; void Func_2(){LCDDATA0 = 0b01011011;} // 2 を表示 //G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1; void Func_3(){LCDDATA0 = 0b01001111;} //3 を表示 //G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1; void Func_4(){LCDDATA0 = 0b01100110;} //4 を表示 //G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0; void Func_5(){LCDDATA0 = 0b01101101;} //5 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1; void Func_6(){LCDDATA0 = 0b01111101;} //6 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1; void Func_7(){LCDDATA0 = 0b00000111;} //7 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1; void Func_8(){LCDDATA0 = 0b01111111;} //8 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1; void Func_9(){LCDDATA0 = 0b01101111;} //9 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1; void Func_A(){LCDDATA0 = 0b01110111;} //A を表示 //G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1; void Func_b(){LCDDATA0 = 0b01111100;} //b を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0; void Func_C(){LCDDATA0 = 0b00111001;} //C を表示 //G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1; void Func_d(){LCDDATA0 = 0b01011110;} //d を表示 //G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0; void Func_E(){LCDDATA0 = 0b01111001;} //E を表示 //G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1; void Func_F(){LCDDATA0 = 0b01110001;} //F を表示 //G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1; void main (void) { TRISCbits.RC1 = 1; // RC1: in //HexSw TRISG = 0xFF; //G port: in //HexSw TRISD = 0x00; //D port: out //Segment Data TRISEbits.RE3 = 0; //COM0: out TRISHbits.RH0 = 1; //HexSw b0 TRISHbits.RH2 = 0; //LED free run // LCDCON (LCD CONTROL)レジスタ LCDCONbits.SLPEN = 0; //Sleep時のLCDドライバーモジュール イネーブル LCDCONbits.WERR = 0; //No LCD Write Erro //LCD Write Failed Error bit LCDCONbits.CS1 = 0; //00 Fosc/4 1x INTRC(31KHz) 00 Sys Clock, 01 TMR1 Clk LCDCONbits.CS0 = 0; // LCDCONbits.LMUX1 = 0; //00 Static(COM0)スタティック制御 //Commons Select bis LCDCONbits.LMUX0 = 0; // LCDPS(LCD PHASE) レジスタ LCDPSbits.WFT = 0; //0 - TypeA(Phase changes whithin each common type) LCDPSbits.BIASMD = 0; //Bias Mode Select bit(スタティックモードでは0にセットのこと) LCDPSbits.LCDA = 0; //LCDドライバモジュールは非アクティブ LCDPSbits.WA = 0; // LCDへの書き込みは許可されていない。 LCDPSbits.LP3 = 0; //0100LP <3:0> LCDクロックのプリスケーラ 1/5 LCDPSbits.LP2 = 1; LCDPSbits.LP1 = 0; LCDPSbits.LP0 = 0; // LCDSEx (LCD SEGMENT ENABLE)レジスタ // 1: セグメント機能モード 0: I/Oモード LCDSE0 = 0xFF; //対応ポート: SEG0-SEG7 //セグメント機能モード LCDSE1 = 0x00; //対応ポート: SEG8-SEG15//デジタルI/Oモード LCDSE2 = 0x00; //対応ポート: SEG16-SE23//デジタルI/Oモード LCDSE3 = 0x00; //対応ポート: SEG24-SEG31//デジタルI/Oモード LCDSE4 = 0x00; //対応ポート: SEG32-SEG39 //デジタルI/Oモード LCDSE5 = 0x00; //対応ポート: SEG40-SEG47 //デジタルI/Oモード // LCDREG(VOLTAGE REGULATOR CONTROL)レジスタ LCDREGbits.CPEN = 0; //LCDチャージポンプOFF// LCD charge Pump Enable bit LCDREGbits.CKSEL1 = 0; //Regulator Clock Source Select bit //LCD レギュレータ ディセーブル // LCDREGbits.CKSEL0 = 0; // LCDCONbits.LCDEN = 1; //LCDドライバーモジュール イネーブル while (1) { if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Func_0(); else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_1(); else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_2(); else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_3(); else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_4(); else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_5(); else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_6(); else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 0)) Func_7(); else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 1)) Func_8(); else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_9(); else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_A(); else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_b(); else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_C(); else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_d(); else if((b3 == 0) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_E(); else Func_F(); } }
<動作結果>
HEXスイッチを5に設定した場合の液晶表示の写真です。
■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 カウンタ
<C18編>
液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
・制御対象は7セグメント液晶1個とする。
・周期1秒の16進カウンタを製作のこと。 また、 Fの次は 0に戻ること
すなわち 0 → 1 → 2 → 3 ……… C → d → E → F → 0 → 1
<試作品回路図>(→回路図のPDFファイル)
PIC18F85J90、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> /* 1秒毎の 16進Counter値を表示 */ #include <p18f85J90.h> #include <stdio.h> #include <delays.h> #include <timers.h> #pragma config FOSC = HS // システムクロック=20MHz #pragma config XINST = OFF #pragma config WDTEN = OFF //ウォッチドックタイマ OFF unsigned long int Count1 = 0; unsigned long int Count2 = 0; int LED = 0; void Func_0(){LCDDATA0 = 0b0111111;} // 0 を表示 //G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1; void Func_1(){LCDDATA0 = 0b00000110;} // 1 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0; void Func_2(){LCDDATA0 = 0b01011011;} // 2 を表示 //G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1; void Func_3(){LCDDATA0 = 0b01001111;} //3 を表示 //G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1; void Func_4(){LCDDATA0 = 0b01100110;} //4 を表示 //G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0; void Func_5(){LCDDATA0 = 0b01101101;} //5 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1; void Func_6(){LCDDATA0 = 0b01111101;} //6 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1; void Func_7(){LCDDATA0 = 0b00000111;} //7 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1; void Func_8(){LCDDATA0 = 0b01111111;} //8 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1; void Func_9(){LCDDATA0 = 0b01101111;} //9 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1; void Func_A(){LCDDATA0 = 0b01110111;} //A を表示 //G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1; void Func_b(){LCDDATA0 = 0b01111100;} //b を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0; void Func_C(){LCDDATA0 = 0b00111001;} //C を表示 //G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1; void Func_d(){LCDDATA0 = 0b01011110;} //d を表示 //G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0; void Func_E(){LCDDATA0 = 0b01111001;} //E を表示 //G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1; void Func_F(){LCDDATA0 = 0b01110001;} //F を表示 //G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1; #pragma interrupt my_Func // 10msec タイマ1 インターバル割り込み #pragma code isrcode = 0x08 void isr_direct(void) { _asm goto my_Func _endasm } #pragma code void my_Func(void) { PIR1bits.TMR1IF = 0; // タイマ1割り込みフラグをクリアする WriteTimer1(59286); // 0.05μsec × 4 × 8 × 6250 = 10000μsec = 10msec (at システムクロック20MHz) // 256×256 - 6250 = 59286 // タイマ0:16bitアップカウントタイマ → オーバーフローで割込み発生 Count1++; if(Count1 >= 100) //1秒毎に { Count1 = 0; if(Count2 == 0)Func_0(); else if(Count2 == 1) Func_1(); else if(Count2 == 2) Func_2(); else if(Count2 == 3) Func_3(); else if(Count2 == 4) Func_4(); else if(Count2 == 5) Func_5(); else if(Count2 == 6) Func_6(); else if(Count2 == 7) Func_7(); else if(Count2 == 8) Func_8(); else if(Count2 == 9) Func_9(); else if(Count2 == 10) Func_A(); else if(Count2 == 11) Func_b(); else if(Count2 == 12) Func_C(); else if(Count2 == 13) Func_d(); else if(Count2 == 14) Func_E(); else Func_F(); Count2++; if(Count2 >= 16)Count2 = 0; if(LED == 1) { PORTDbits.RD1 = 0; // RD1 LED ON LED = 0; } else { PORTDbits.RD1 = 1; // BポートのLED OFF LED = 1; } } } void main (void) { TRISCbits.RC1 = 1; // RC1: in //HexSw TRISG = 0xFF; //G port: in //HexSw TRISD = 0x00; //D port: out //Segment Data TRISEbits.RE3 = 0; //COM0: out TRISHbits.RH0 = 1; //HexSw b0 TRISHbits.RH2 = 0; //LED free run // LCDCON (LCD CONTROL)レジスタ LCDCONbits.SLPEN = 0; //Sleep時のLCDドライバーモジュール イネーブル LCDCONbits.WERR = 0; //No LCD Write Erro //LCD Write Failed Error bit LCDCONbits.CS1 = 0; //00 Fosc/4 1x INTRC(31KHz) 00 Sys Clock, 01 TMR1 Clk LCDCONbits.CS0 = 0; // LCDCONbits.LMUX1 = 0; //00 Static(COM0)スタティック制御 //Commons Select bis LCDCONbits.LMUX0 = 0; // LCDPS(LCD PHASE) レジスタ LCDPSbits.WFT = 0; //0 - TypeA(Phase changes whithin each common type) LCDPSbits.BIASMD = 0; //Bias Mode Select bit(スタティックモードでは0にセットのこと) LCDPSbits.LCDA = 0; //LCDドライバモジュールは非アクティブ LCDPSbits.WA = 0; // LCDへの書き込みは許可されていない。 LCDPSbits.LP3 = 0; //0100LP <3:0> LCDクロックのプリスケーラ 1/5 LCDPSbits.LP2 = 1; //31000Hz / 5 = 6200Hz LCDPSbits.LP1 = 0; LCDPSbits.LP0 = 0; // LCDSEx (LCD SEGMENT ENABLE)レジスタ // 1: セグメント機能モード 0: I/Oモード LCDSE0 = 0xFF; //対応ポート: SEG0-SEG7 //セグメント機能モード LCDSE1 = 0x00; //対応ポート: SEG8-SEG15//デジタルI/Oモード LCDSE2 = 0x00; //対応ポート: SEG16-SE23//デジタルI/Oモード LCDSE3 = 0x00; //対応ポート: SEG24-SEG31//デジタルI/Oモード LCDSE4 = 0x00; //対応ポート: SEG32-SEG39 //デジタルI/Oモード LCDSE5 = 0x00; //対応ポート: SEG40-SEG47 //デジタルI/Oモード // LCDREG(VOLTAGE REGULATOR CONTROL)レジスタ LCDREGbits.CPEN = 0; //LCDチャージポンプOFF// LCD charge Pump Enable bit LCDREGbits.CKSEL1 = 0; //Regulator Clock Source Select bit //LCD レギュレータ ディセーブル // LCDREGbits.CKSEL0 = 0; // LCDCONbits.LCDEN = 1; //LCDドライバーモジュール イネーブル //タイマ1の設定 OpenTimer1 ( TIMER_INT_ON & //割込み:ON T1_16BIT_RW & //16 bit モードに設定 vs 8bit モード( T0_8BIT ) T1_SOURCE_INT & //内部クロック使用 T1_PS_1_8 & //8ビットプリスケーラ 1/8 vs 1/1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 T1_OSC1EN_OFF ); WriteTimer1(59286); RCONbits.IPEN = 0; //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0) PIE1bits.TMR1IE = 1; //タイマ1割込み許可 INTCONbits.PEIE =1; //周辺割込み許可 //INTCONレジスタの b6ビット : 低位割込み許可/禁止(割り込み優先順位制御 有りの場合) INTCONbits.GIE = 1; //全割込み許可 //INTCONレジスタの b7ビット : 高位割込み許可/禁止(割り込み優先順位制御 有りの場合) while (1) { } } <動作結果> カウンタ値が3の場合の写真です。